% !Mode:: "TeX:UTF-8"

\section{项目设计与实现}

\subsection{硬件设计}

\subsubsection{系统总体架构}
系统采用模块化设计，以STM32F103C8T6微控制器为核心，通过外围电路实现蓝牙通信、电机驱动、温湿度采集、人体感应等关键功能。系统架构包含主控制器模块、蓝牙通信模块、电机驱动模块、电源模块、温湿度采集模块和人体感应模块。

\subsubsection{主控制器模块}
选用STM32F103C8T6微控制器作为主控芯片，主要特性包括：
- 72MHz Cortex-M3内核
- 64KB Flash, 20KB SRAM
- 3个通用定时器（TIM2/TIM3/TIM4）
- 丰富的GPIO接口
- 12位ADC转换器

\subsubsection{蓝牙通信模块}
通过USART1实现蓝牙通信功能，主要特性：
\begin{itemize}
    \item 工作电压：3.3V
    \item 通信波特率：9600
    \item 连接方式：\texttt{TX}引脚 $\rightarrow$ \texttt{PA9}（复用推挽输出），\texttt{RX}引脚 $\rightarrow$ \texttt{PA10}（浮空输入）
    \item 功能：接收外部蓝牙指令，控制电机运行状态
\end{itemize}

\subsubsection{电机驱动模块}
\paragraph{L298N电机驱动方案}
采用L298N双H桥驱动芯片驱动直流电机：
\begin{itemize}
    \item \texttt{AIN1/AIN2} $\rightarrow$ \texttt{PA4/PA5}（推挽输出），控制电机转向
    \item \texttt{PWM} $\rightarrow$ \texttt{PA2}（PWM输出），控制电机速度
\end{itemize}
通过调节PWM占空比实现速度连续调节（0-100\%）

\subsubsection{电源模块}
设计双电源供电方案：
- 主控电路：AMS1117-3.3V稳压芯片，输入5V→输出3.3V
- 电机电路：LM2596降压模块，输入12V→输出12V（最大电流2A）
- USB接口提供5V调试电源

\subsubsection{温湿度采集模块}
采用DHT11温湿度传感器：
\begin{itemize}
    \item 工作电压：3.3-5V
    \item 连接方式：\texttt{DATA}引脚 $\rightarrow$ \texttt{PA0}（双向IO）
    \item 测量范围：温度0-50℃，湿度20-90\%RH
\end{itemize}

\subsubsection{人体感应模块}
采用PIR红外人体传感器：
\begin{itemize}
    \item 工作电压：3.3-5V
    \item 连接方式：\texttt{OUT}引脚 $\rightarrow$ \texttt{PA8}（上拉输入）
    \item 检测范围：5-7米，110°视角
\end{itemize}

\subsubsection{显示与交互模块}
- OLED显示屏：通过I2C通信（\texttt{PB8/SCL}, \texttt{PB9/SDA}），显示系统状态信息
- 按键：\texttt{PB0}和\texttt{PB10}（上拉输入），用于模式切换和菜单选择

\subsection{软件设计}

\subsubsection{系统软件架构}
软件采用分层设计：
1. 硬件抽象层（HAL）：系统时钟配置、GPIO初始化等底层代码
2. 驱动层：PWM输出（pwm.c）、电机驱动（motor.c）、蓝牙通信（usart.c）、延时（delay.c）、按键（key.c）、OLED显示（oled.c）、温湿度采集（dht11.c）、人体感应（pir.c）
3. 应用层：主控制逻辑（main.c）、状态管理、用户接口交互

\subsubsection{主程序流程}
系统采用中断驱动+状态机设计：
\begin{enumerate}
    \item 系统初始化（时钟、GPIO、各模块初始化）
    \item 进入主循环，通过按键扫描检测用户输入
    \item 根据系统当前模式（\texttt{currentMode}）执行对应处理逻辑
    \item 串口中断服务程序处理蓝牙接收数据
    \item 定时更新系统状态并在OLED显示
\end{enumerate}

\subsubsection{蓝牙指令协议实现}
通过USART1接收蓝牙指令，指令格式：
- 0x00：电机停止
- 0x01：电机正转
- 0x02：电机反转
- 0-100（数值）：设置电机速度（0为停止，100为最大速度）

\begin{center}
    \resizebox{0.95\textwidth}{!}{%
    \begin{tabular}{|l|l|}
      \hline
      \textbf{蓝牙指令} &  \textbf{系统响应} \\
      \hline
      0x00  & 控制电机停止运行 \\
      \hline
      0x01  & 控制电机正转 \\
      \hline
      0x02  & 控制电机反转 \\
      \hline
      0-100  & 设置电机速度（0-100\%） \\
      \hline
    \end{tabular}%
    }
\end{center}

\subsection{代码介绍}

\subsubsection{初始化和配置}
\begin{itemize}
    \item \begin{verbatim}SystemClock_Config()：\end{verbatim}配置系统时钟为72MHz，使能各外设时钟
    \begin{lstlisting}[language=C]
void SystemClock_Config(void) {
    SystemInit();
    RCC_DeInit();
    RCC_HSEConfig(RCC_HSE_ON);
    while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
    
    RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
    RCC_PLLCmd(ENABLE);
    while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
    
    RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
    while(RCC_GetSYSCLKSource() != 0x08);
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | 
                          RCC_APB2Periph_AFIO | RCC_APB2Periph_USART1, ENABLE);
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
}
    \end{lstlisting}
    
    \item \begin{verbatim}delay_init()：\end{verbatim}初始化SysTick定时器，实现us和ms级延时
    \begin{lstlisting}[language=C]
void delay_init() {
    SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);
    fac_us = SystemCoreClock / 8000000;
    fac_ms = fac_us * 1000;
}
    \end{lstlisting}
    
    \item \begin{verbatim}OLED_Init()：\end{verbatim}初始化OLED显示屏，配置I2C通信参数
    \begin{lstlisting}[language=C]
void OLED_Init(void) {
    I2C_Soft_Init();
    delay_ms(100);
    
    OLED_WriteCmd(0xAE); // 关闭显示
    OLED_WriteCmd(0xD5); // 设置时钟分频
    OLED_WriteCmd(0x80);
    OLED_WriteCmd(0xA8); // 设置复用率
    OLED_WriteCmd(0x3F);
    // 省略部分配置指令
    OLED_WriteCmd(0xAF); // 开启显示
    OLED_Clear();
}
    \end{lstlisting}
    
    \item \begin{verbatim}Motor_Init()：\end{verbatim}初始化电机驱动GPIO和PWM（TIM2）
    \begin{lstlisting}[language=C]
void Motor_Init(void) {
    GPIO_InitTypeDef GPIO_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    
    GPIO_InitStructure.GPIO_Pin = AIN1_PIN | AIN2_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    PWM_Init(GPIO_Pin_2);
    Motor_Stop();
}
    \end{lstlisting}
    
    \item \begin{verbatim}USART1_Init(9600)：\end{verbatim}初始化串口通信，使能接收中断
    \begin{lstlisting}[language=C]
void USART1_Init(uint32_t baudrate) {
    GPIO_InitTypeDef GPIO_InitStructure;
    USART_InitTypeDef USART_InitStructure;
    NVIC_InitTypeDef NVIC_InitStructure;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    
    // 配置TX/RX引脚
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置串口参数
    USART_InitStructure.USART_BaudRate = baudrate;
    USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    USART_InitStructure.USART_StopBits = USART_StopBits_1;
    USART_InitStructure.USART_Parity = USART_Parity_No;
    USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    USART_Init(USART1, &USART_InitStructure);
    
    // 使能接收中断
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    
    // 配置中断优先级
    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    
    USART_Cmd(USART1, ENABLE);
}
    \end{lstlisting}
\end{itemize}

\subsubsection{主功能实现}
\begin{itemize}
    \item \begin{verbatim}KEY_Scan()：\end{verbatim}按键扫描函数，处理模式切换和菜单选择
    \begin{lstlisting}[language=C]
void KEY_Scan(void) {
    static uint8_t key1_last = 1, key2_last = 1;
    uint8_t key1_current = KEY1;
    uint8_t key2_current = KEY2;
    
    if(!key1_last && key1_current) {
        key1_pressed = 1;
    }
    key1_last = key1_current;
    
    if(!key2_last && key2_current) {
        key2_pressed = 1;
    }
    key2_last = key2_current;
    
    if(key1_pressed) {
        key1_pressed = 0;
        if(currentMode == MODE_SELECTION) {
            menu_selection = !menu_selection;
            OLED_Clear();
            OLED_ShowString(0, 0, "Mode Select:", 16);
            OLED_ShowString(0, 2, menu_selection==0?">Bluetooth":" Bluetooth", 16);
            OLED_ShowString(0, 4, menu_selection==1?">Auto Mode":" Auto Mode", 16);
        } 
        else if(currentMode == AUTO_MODE_MENU) {
            currentSubMenu = (currentSubMenu + 1) % 3;
            // 更新自动模式菜单显示
        }
    }
    
    if(key2_pressed) {
        key2_pressed = 0;
        if(currentMode == MODE_SELECTION) {
            currentMode = menu_selection ? AUTO_MODE_MENU : BLUETOOTH_MODE;
            // 切换模式显示
        } 
        else if(currentMode == AUTO_MODE_MENU) {
            if(currentSubMenu == PIR_CTRL) {
                pirEnabled = !pirEnabled;
            }
            currentMode = AUTO_MODE_RUNNING;
            OLED_Clear();
        }
    }
}
    \end{lstlisting}
    
    \item \begin{verbatim}Bluetooth_Mode_Handler()：\end{verbatim}蓝牙模式处理函数
          \begin{itemize}
              \item 显示电机速度和方向信息
              \item 响应蓝牙指令控制电机
          \end{itemize}
    \begin{lstlisting}[language=C]
void Bluetooth_Mode_Handler(void) {
    OLED_ShowString(0, 0, "Bluetooth Mode", 16);
    OLED_ShowString(0, 2, "Speed:", 16);
    OLED_ShowNum(60, 2, motorSpeed, 3, 16);
    OLED_ShowString(0, 4, "Dir:", 16);
    OLED_ShowString(40, 4, motorDirection==1?"FWD":motorDirection==2?"REV":"STOP", 16);
}
    \end{lstlisting}
    
    \item \begin{verbatim}Auto_Mode_Handler()：\end{verbatim}自动模式处理函数
          \begin{itemize}
              \item 通过DHT11读取温湿度数据
              \item 通过PIR检测人体存在
              \item 根据检测数据自动控制电机运行
              \item 每1秒更新一次状态
          \end{itemize}
    \begin{lstlisting}[language=C]
void Auto_Mode_Handler(void) {
    if(DHT11_Read_Data(&temperature, &humidity)) {
        uint8_t humanDetected = PIR_Read();
        uint16_t calcSpeed = 0;
        
        if(pirEnabled && humanDetected) {
            switch(currentSubMenu) {
                case TEMP_CTRL:
                    calcSpeed = temperature * 2;
                    break;
                case HUMIDITY_CTRL:
                    calcSpeed = humidity ;
                    break;
                case PIR_CTRL:
                    calcSpeed = 50; // 默认速度
                    break;
            }
            motorDirection = 1; // 正转
            motorSpeed = (calcSpeed > 100) ? 100 : calcSpeed;
        } else {
            motorSpeed = 0;
            motorDirection = 0;
        }
        
        Motor_SetSpeed(motorSpeed);
        Motor_SetDirection(motorDirection);
        
        // 更新OLED显示温湿度、PIR状态、电机参数
        OLED_Clear();
        OLED_ShowString(0, 0, "Temp:", 16);
        OLED_ShowNum(50, 0, temperature, 2, 16);
        OLED_ShowString(70, 0, "C", 16);
        // 省略部分显示代码
    }
}
    \end{lstlisting}
\end{itemize}

\subsubsection{特定条件响应}
\begin{itemize}
    \item \begin{verbatim}USART1_IRQHandler()：\end{verbatim}串口中断服务函数，处理蓝牙接收数据
    \begin{lstlisting}[language=C]
void USART1_IRQHandler(void) {
    if(USART_GetITStatus(USART1, USART_IT_RXNE)) {
        uint8_t data = USART_ReceiveData(USART1);
        
        if(currentMode == BLUETOOTH_MODE) {
            switch(data) {
                case 0x01: // 正转
                    Motor_SetDirection(1);
                    break;
                case 0x02: // 反转
                    Motor_SetDirection(2);
                    break;
                case 0x00: // 停止
                    Motor_Stop();
                    break;
                default:   // 设置速度 (0-100)
                    if(data <= 100) {
                        Motor_SetSpeed(data);
                    }
                    break;
            }
        }
    }
}
    \end{lstlisting}
    
    \item 按键状态变化时，切换系统模式或菜单选项
    \item 自动模式下，无人检测时自动停止电机
\end{itemize}

\subsubsection{循环体结构}
\begin{itemize}
    \item \begin{verbatim}while (1) {
  KEY_Scan();
  switch(currentMode) {
    case BLUETOOTH_MODE:
      Bluetooth_Mode_Handler();
      break;
    case AUTO_MODE_RUNNING:
      Auto_Mode_Handler();
      delay_ms(1000);
      break;
    // 其他模式处理
  }
}\end{verbatim}主循环根据系统模式执行对应处理逻辑
\end{itemize}

\subsection{技术实现细节}
\subsubsection{PWM调速实现}
使用TIM2产生PWM信号，通过改变占空比调节电机速度：
\begin{align*}
\text{占空比} = \frac{\text{脉冲宽度}}{\text{周期}} \times 100\%
\end{align*}
通过\texttt{PWM_SetDuty()}函数设置占空比（0-100），对应TIM2的CCR3寄存器值

\subsubsection{自动控制逻辑实现}
采用多条件判断实现智能控制：
\begin{enumerate}
    \item 检测人体感应状态（\texttt{PIR_Read()}）
    \item 根据选中的控制模式（温度/湿度/人体感应）计算电机速度
    \item 温度控制：速度 = 温度 × 2（限制最大100）
    \item 湿度控制：速度 = 湿度值（限制最大100）
    \item 人体感应控制：固定速度50
\end{enumerate}

\subsubsection{状态机设计}
系统通过全局变量\texttt{currentMode}管理运行状态：
\begin{itemize}
    \item \texttt{MODE_SELECTION}：模式选择界面
    \item \texttt{AUTO_MODE_MENU}：自动模式菜单
    \item \texttt{BLUETOOTH_MODE}：蓝牙控制模式
    \item \texttt{AUTO_MODE_RUNNING}：自动运行模式
\end{itemize}
通过按键操作在不同状态间切换，提高系统灵活性和可操作性
